﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Vbyte.SharpOrm.SqlDb;
using Vbyte.SharpOrm.Adapter;
using Vbyte.Configuration;

namespace Vbyte.SharpOrm.Config
{
    /// <summary>
    /// 数据库适配及提供者配置
    /// </summary>
    /// <remarks>
    /// 内置实现配置如下：(SQLServer/Access)
    /// <code>
    ///   <SharpOrm.ProviderConfig type="Vbyte.SharpOrm.Config.ProviderConfig, Vbyte.SharpOrm">
    ///     <add ProviderName="System.Data.SqlClient" DbType="Vbyte.SharpOrm.SqlDb.SqlServer" 
    ///         AdapterType="Vbyte.SharpOrm.Adapter.SqlServerAdapter" BuilderType="Vbyte.SharpOrm.Adapter.MsSqlBuilderAdapter" 
    ///         ConstrainsType="Vbyte.SharpOrm.SqlDb.SqlNativeConstrains" />
    ///   </SharpOrm.ProviderConfig>
    /// </code>
    /// </remarks>
    [Serializable]
    [XmlRoot("SharpOrm.ProviderConfig")]
    public class ProviderConfig
    {
        /// <summary>
        /// 相关实现配置
        /// </summary>
        [XmlElement(ElementName = "add")]
        public OrmImplement[] Implements { get; set; }

        private static ProviderConfig _instance;
        /// <summary>
        /// 获取配置文件中的实例
        /// </summary>
        public static ProviderConfig ConfigInstance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = XmlSerializeSectionHandler.GetObject<ProviderConfig>("SharpOrm.ProviderConfig");
                }
                return _instance;
            }
        }

        #region 实例获取辅助
        /// <summary>
        /// 约束缓存词典
        /// </summary>
        internal static Dictionary<string, ISqlConstrains> ConstrainsDict = new Dictionary<string, ISqlConstrains>();

        /// <summary>
        /// 数据库操作辅助实例缓存词典
        /// </summary>
        internal static Dictionary<string, ISqlDb> SqlDbDict = new Dictionary<string, ISqlDb>();

        /// <summary>
        /// 数据库ORM操作适配缓存词典
        /// </summary>
        internal static Dictionary<string, ISqlDbAdapter> AdapterDict = new Dictionary<string, ISqlDbAdapter>();

        /// <summary>
        /// SQL构建实现缓存词典
        /// </summary>
        internal static Dictionary<string, ISqlBuilderAdapter> BuilderDict = new Dictionary<string, ISqlBuilderAdapter>();

        /// <summary>
        /// 根据实现配置获取实例约束实现类型（默认获取为<c>SqlNativeConstrains</c>）
        /// </summary>
        /// <param name="impType">实现类型的字符串</param>
        /// <param name="connKey">应用到的连接字符串键名，为空或null则忽略。</param>
        /// <returns>实例约束实现类型</returns>
        public static ISqlConstrains GetSqlConstrains(string impType, string connKey)
        {
            if (string.IsNullOrEmpty(impType))  return new SqlNativeConstrains();
            return GetConfigInstance<ISqlConstrains>(impType, connKey, typeof(ISqlConstrains), ConstrainsDict);
        }


        /// <summary>
        /// 根据实现配置获取数据库操作辅助实例
        /// </summary>
        /// <param name="impType">实现类型的字符串</param>
        /// <param name="connKey">应用到的连接字符串键名，为空或null则忽略。</param>
        /// <returns>数据库操作辅助实例</returns>
        public static ISqlDb GetSqlDb(string impType, string connKey)
        {
            return GetConfigInstance<ISqlDb>(impType, connKey, typeof(ISqlDb), SqlDbDict);
        }

        /// <summary>
        ///  根据实现配置获取SQL构建实例
        /// </summary>
        /// <param name="impType">实现类型的字符串</param>
        /// <param name="connKey">应用到的连接字符串键名，为空或null则忽略。</param>
        /// <returns>SQL构建适配实现</returns>
        public static ISqlBuilderAdapter GetSqlBuilder(string impType, string connKey)
        {
            return GetConfigInstance<ISqlBuilderAdapter>(impType, connKey, typeof(ISqlBuilderAdapter), BuilderDict);
        }

        /// <summary>
        /// 根据实现配置获取数据库操作适配实例
        /// </summary>
        /// <param name="impType">实现类型的字符串</param>
        /// <param name="connKey">应用到的连接字符串键名，为空或null则忽略。</param>
        /// <returns>数据库操作适配实例</returns>
        public static ISqlDbAdapter GetSqlAdapter(string impType, string connKey)
        {
            return GetConfigInstance<ISqlDbAdapter>(impType, connKey, typeof(ISqlDbAdapter), AdapterDict);
        }

        private static T GetConfigInstance<T>(string impType, string connKey, Type interfaceType, Dictionary<string, T> CacheDict)
        {
            string dictKey = string.IsNullOrEmpty(connKey) ? impType : string.Concat(impType, ":", connKey);
            if (!CacheDict.ContainsKey(dictKey))
            {
                Type tType = Type.GetType(impType, false);
                if (tType == null)
                {
                    throw new System.Configuration.ConfigurationErrorsException("配置错误，没有找到实现类型" + impType + "！");
                }
                else
                {
                    if (tType.GetInterface(interfaceType.FullName, false) == null)
                    {
                        throw new System.Configuration.ConfigurationErrorsException("配置错误，类型" + impType + "不没有实现接口" + interfaceType.FullName + "！");
                    }

                    object targetInstance = null;
                    try
                    {
                        targetInstance = Activator.CreateInstance(tType);
                    }
                    catch (Exception exp)
                    {
                        throw new InvalidOperationException("创建实例操作失败，可能时没有公开的无参数构造方法。", exp);
                    }

                    if (targetInstance != null)
                    {
                        CacheDict.Add(dictKey, (T)targetInstance);
                    }
                }
            }
            return CacheDict[dictKey];
        }

        #endregion
    }


    /// <summary>
    /// 相关实现配置（有应用键值的同类提供者实现配置必须放在最前面）
    /// </summary>
    [Serializable]
    public class OrmImplement
    {
        /// <summary>
        /// 获取或设置相关数据提供者
        /// </summary>
        [XmlAttribute]
        public string ProviderName { get; set; }

        /// <summary>
        /// 获取或设置应用到的连接字符串键名（可选）
        /// </summary>
        [XmlAttribute]
        public string ApplyKey { get; set; }
        
        /// <summary>
        /// 获取或设置数据库(表)创建维护辅助实现类型（实现接口Vbyte.SharpOrm.SqlDb.ISqlDb）
        /// </summary>
        [XmlAttribute]
        public string DbType { get; set; }

        /// <summary>
        /// 获取或设置数据操作差异实现类型（实现接口Vbyte.SharpOrm.Adapter.ISqlDbAdapter）
        /// </summary>
        [XmlAttribute]
        public string AdapterType { get; set; }

        /// <summary>
        /// 获取或设置SQL构建实现类型（实现接口Vbyte.SharpOrm.Adapter.ISqlBuilderAdapter）
        /// </summary>
        [XmlAttribute]
        public string BuilderType { get; set; }

        /// <summary>
        /// 获取或设置实例约束实现类型，默认为<c>Vbyte.SharpOrm.SqlDb.SqlNativeConstrains</c>。（实现接口Vbyte.SharpOrm.SqlDb.ISqlConstrains）
        /// </summary>
        [XmlAttribute]
        public string ConstrainsType { get; set; }

    }

}
